package com.gudy.engine.bean.orderbook;

import com.gudy.engine.bean.command.RbCmd;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import thirdpart.order.OrderStatus;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;

@Log4j2
@ToString
public class GOrderBucketImpl implements IOrderBucket {

    AtomicLong tidGen = new AtomicLong(0);

    //价格
    @Getter
    @Setter
    private long price;

    /**量*/
    private long totalVolume = 0;

    /**委托列表 list不行*/
    private final LinkedHashMap<Long, Order> entries=new LinkedHashMap<>();



    @Override
    public void put(Order order) {
        entries.put(order.getOid(),order);
        totalVolume += order.getVolume()-order.getTvolume();
    }

    @Override
    public Order remove(long id) {
        Order order = entries.get(id);
        if ( order == null){
            return null;
        }
        entries.remove(id);
        totalVolume -=order.getVolume()-order.getTvolume();
        return order;
    }

    @Override
    public long match(long volumeLeft, RbCmd triggerCmd, Consumer<Order> removeOrderCallback) {
        Iterator<Map.Entry<Long, Order>> iterator = entries.entrySet().iterator();
        long volumnMatch=0;
        while (iterator.hasNext() && volumeLeft>0){
            Map.Entry<Long, Order> next = iterator.next();
            Order order = next.getValue();
            long traded = Math.min(volumeLeft, order.getVolume() - order.getTvolume());
            volumnMatch += traded;
            order.setTvolume(order.getTvolume()+traded);
            volumeLeft -= traded;
            totalVolume -= traded;

            boolean fullMatch = order.getVolume() == order.getTvolume();
            genMatchEvent(order,triggerCmd,fullMatch,volumeLeft==0,traded);

            if(fullMatch){
                removeOrderCallback.accept(order);
                iterator.remove();
            }
        }
        return volumnMatch;
    }

    private void genMatchEvent(final Order order, final RbCmd cmd, boolean fullMatch, boolean cmdFullMatch, long traded) {
        long now = System.currentTimeMillis();
        long tid = tidGen.getAndIncrement();

        // 两个MatchEvent
        MatchEvent bidEvent = new MatchEvent();
        bidEvent.timestamp=now;
        bidEvent.mid=cmd.mid;
        bidEvent.oid = cmd.oid;
        bidEvent.status = cmdFullMatch? OrderStatus.TRADE_ED:OrderStatus.PART_TRADE;
        bidEvent.tid = tid;
        bidEvent.volume = traded;
        bidEvent.price = order.getPrice();
        cmd.matchEventList.add(bidEvent);

        MatchEvent ofrEvent = new MatchEvent();
        bidEvent.timestamp=now;
        bidEvent.mid=order.getMid();
        bidEvent.oid = order.getOid();
        bidEvent.status = cmdFullMatch? OrderStatus.TRADE_ED:OrderStatus.PART_TRADE;
        bidEvent.tid = tid;
        bidEvent.volume = traded;
        bidEvent.price = order.getPrice();
        cmd.matchEventList.add(bidEvent);

        //
    }

    @Override
    public long getTotalVolume() {
        return 0;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        GOrderBucketImpl that = (GOrderBucketImpl) o;

        return new EqualsBuilder()
                .append(price, that.price)
                .append(entries, that.entries)
                .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37)
                .append(price)
                .append(entries)
                .toHashCode();
    }
}
